﻿///////////////////////////////////////////////////////////////////////////////
// File Name: ObjectSkin.cpp
// Author: 张东斌、ChongyangLee
// E_Mail: malutianshi7905@sina.com; ChongyangLee@hotmail.com
// History: 
// 2009/09/26 Add 控件ID 列表的串行化
// 2009/09/26 Add 控件ID 的设置、或取与查找
// 2009/10/12 Add 操作系统版本，
///////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "objectskin.h"
#include "Skin.h"
#include <set>
using namespace std;
using std::set;

/////////////////////////////////////////////////////
IMPLEMENT_SERIAL(CObjectSkin,CObject,1)

CObjectSkin::CObjectSkin(const char* szName,int nType )
: m_strName(szName)
, m_nSkinType(nType)
, m_strTag(_T(""))
, m_pParent(NULL)
, m_szMax(0,0)
, m_szMin(0,0)
, m_rtPosition(0,0,300,200)
, m_rtOffset(0,0,0,0)
, m_rtAnchors(0,0,0,0)
, m_nAnchorType(0)
, m_nCtlID(0)
, m_nSkinVersion(1)// 默认初始化为 第一个版本
{
	// 操作系统版本
	OSVERSIONINFO osvi;
	osvi.dwOSVersionInfoSize = sizeof(osvi);
	GetVersionEx(&osvi);
	m_dwOSVersionMajor = osvi.dwMajorVersion;
	m_dwOSVersionMinor = osvi.dwMinorVersion;
}

CObjectSkin::~CObjectSkin(void)
{
	ClearChild();
}
void CObjectSkin::Serialize(CArchive &ar)
{
	CObject::Serialize(ar);
	if(ar.IsStoring())
	{
		ar <<m_nAnchorType<< m_rtPosition << m_rtOffset << m_rtAnchors << m_szMin << m_szMax << m_nSkinType
			<< m_strName << m_strTag ;
		unsigned int nSZ = m_setCtlID.size();
		ar << nSZ;
		for(set<int>::iterator iter = m_setCtlID.begin();
			iter != m_setCtlID.end(); ++iter)
		{
			ar << *iter;
		}
	}
	else
	{
		ar >>m_nAnchorType>> m_rtPosition >> m_rtOffset >> m_rtAnchors >> m_szMin >> m_szMax >> m_nSkinType
			>> m_strName >> m_strTag;

		switch(m_nSkinVersion)
		{
		case 2:
			{
				unsigned int nCount = 0;
				ar >> nCount;
				for(unsigned int i = 0; i < nCount; ++ i)
				{
					int nID;
					ar >> nID;
					m_setCtlID.insert(nID);
				}
			}
		case 1:
		default:
			{
				break;
			}
		}
		
	}
}
void CObjectSkin::AddChild(CObjectSkin *pObjectSkin)
{
	if(pObjectSkin == NULL)
		return;
	pObjectSkin->SetParent(this);
	m_arrayChildrens.Add(pObjectSkin);
}

void CObjectSkin::DeleteChild(const CString& strName)
{
	CObjectSkin *pChild = NULL;
	for(int i = 0 ; i < m_arrayChildrens.GetSize(); i++)
	{
		pChild = m_arrayChildrens.GetAt(i);
		if(pChild ->GetName() == strName)
		{
			delete pChild;
			m_arrayChildrens.RemoveAt(i);
		}
	}
}

void CObjectSkin::ClearChild()
{
	for(int i = 0 ; i < m_arrayChildrens.GetSize(); ++i)
	{
		CObjectSkin *pChild = m_arrayChildrens.GetAt(i);
		if(pChild != NULL)
			delete pChild;
	}

	m_arrayChildrens.RemoveAll();
}

int	CObjectSkin::GetChildrenCount()
{
	return (int)m_arrayChildrens.GetSize();
}

// 
SkinLogFont CObjectSkin::GetDefaultFont()
{
	static SkinLogFont font;
	static bool fInit = false;
	if(!fInit)
	{
		NONCLIENTMETRICS nif;
		nif.cbSize = sizeof(nif);
#if (WINVER >= 0x0600)
		// 如果当前定义的 Window 版本 不低于 Vista ,但实际运行版本低 需要修正 nif.cbsize
		// 参考 NONCLIENTMETRICS 定义
		if(m_dwOSVersionMajor < 6)
		{
			nif.cbSize -= sizeof(nif.iPaddedBorderWidth);					
		}
#endif// 
		SystemParametersInfo(SPI_GETNONCLIENTMETRICS,sizeof(NONCLIENTMETRICS),&nif,0);
		fInit = true;
		font = nif.lfCaptionFont;
	}
	return font;
}

CObjectSkin* CObjectSkin::GetAt(int nIndex)
{
	int nCount = m_arrayChildrens.GetSize();
	if(nIndex >= nCount)
		return NULL;
	CObjectSkin *pObject = NULL;
	pObject = m_arrayChildrens.GetAt(nIndex);
	return pObject;
}

CObjectSkin* CObjectSkin::GetParent()
{
	return m_pParent;
}

void CObjectSkin::SetParent(CObjectSkin *pObjectSkin)
{
	m_pParent = pObjectSkin;
}

CObjectSkin* CObjectSkin::FindChild(const char* strName) const
{
	CObjectSkin* pObjectSkin = NULL;
	for(int i = 0 ; i < m_arrayChildrens.GetSize(); i++)
	{
		pObjectSkin = m_arrayChildrens.GetAt(i);
		if(strcmp(pObjectSkin->GetName(), strName) == 0)
			return pObjectSkin;
	}
	return pObjectSkin;
}
void CObjectSkin::CalcOffset()
{
	if(m_pParent != NULL)
	{
		CRect rectParent	= m_pParent->GetPosition();
		m_rtOffset.left		= m_rtPosition.left - rectParent.Width()*m_rtAnchors.left/100;
		m_rtOffset.top		= m_rtPosition.top	- rectParent.Height()*m_rtAnchors.top/100;
		m_rtOffset.right	= m_rtPosition.right - rectParent.Width()*m_rtAnchors.right/100;
		m_rtOffset.bottom	= m_rtPosition.bottom - rectParent.Height()*m_rtAnchors.bottom/100;
	}
}

void CObjectSkin::CalcPosition()
{
	if(m_pParent != NULL)
	{
		CRect rectParent	= m_pParent->GetPosition();

		m_rtPosition.left = rectParent.Width() * m_rtAnchors.left/100 + m_rtOffset.left;
		m_rtPosition.top = rectParent.Height() * m_rtAnchors.top/100 + m_rtOffset.top;
		m_rtPosition.right = rectParent.Width() * m_rtAnchors.right/100 + m_rtOffset.right;
		m_rtPosition.bottom = rectParent.Height() * m_rtAnchors.bottom/100 + m_rtOffset.bottom;
	}
	CObjectSkin *pObjectSkin = NULL;
	for(int i = 0 ; i < m_arrayChildrens.GetSize() ;i ++)
	{
		pObjectSkin = m_arrayChildrens.GetAt(i);
		if(pObjectSkin)
			pObjectSkin->CalcPosition();
	}
}
CRect CObjectSkin::CalcPosition(const CRect&  rtParent)
{
	CRect rtPosition;
	rtPosition.left		= rtParent.Width() * m_rtAnchors.left/100 + m_rtOffset.left;
	rtPosition.top		= rtParent.Height() * m_rtAnchors.top/100 + m_rtOffset.top;
	rtPosition.right	= rtParent.Width() * m_rtAnchors.right/100 + m_rtOffset.right;
	rtPosition.bottom	= rtParent.Height() * m_rtAnchors.bottom/100 + m_rtOffset.bottom;
	rtPosition.OffsetRect(rtParent.left,rtParent.top);
	return rtPosition;
}
void CObjectSkin::DrawSkin(CDC *pDC)
{

}
int CObjectSkin::GetWidth()
{
	return m_rtPosition.Width();
}
int CObjectSkin::GetHeight()
{
	return m_rtPosition.Height();
}
void CObjectSkin::SetName( const CString& strName )
{
	m_strName = strName; 
}
CString	CObjectSkin::GetName()
{
	return m_strName; 
}
void CObjectSkin::SetTag( const CString& strTag )
{
	m_strTag = strTag;
}
CString	CObjectSkin::GetTag()
{
	return m_strTag; 
}
void CObjectSkin::SetSkinType(int nSkinType)
{
	m_nSkinType = nSkinType; 
}
int	CObjectSkin::GetSkinType()
{
	return m_nSkinType; 
}
void CObjectSkin::SetPosition(const SkinRect &rect)
{
	m_rtPosition = rect; 
}
SkinRect CObjectSkin::GetPosition()
{
	return m_rtPosition; 
}
void CObjectSkin::SetOffset(const SkinRect &offset)
{
	m_rtOffset = offset; 
}
SkinRect CObjectSkin::GetOffset()
{
	return m_rtOffset;
}
void CObjectSkin::SetAnchors(int anchorType)
{
	m_nAnchorType = anchorType;m_rtAnchors = anchorsType[anchorType];
}
int CObjectSkin::GetAnchors()
{
	return m_nAnchorType;
}
void CObjectSkin::SetID(int nID)
{
	m_nCtlID = nID;
}
int	CObjectSkin::GetID()
{
	return m_nCtlID;
}


void CObjectSkin::SetID(const CString & str)
{
	m_setCtlID.clear();
	int nLength = str.GetLength();
	for(int nStart = 0; nStart < nLength; )
	{
		int nPos = str.Find(_T(','), nStart); 
		nPos = (nPos == -1) ? nLength : nPos;
		CString stmp = str.Mid(nStart, nPos - nStart);
		m_setCtlID.insert(atoi(stmp));
		nStart = nPos + 1;
	}
}

void CObjectSkin::GetID(CString & str) const
{
	str.Empty();
	
	for(set<int>::const_iterator iter = m_setCtlID.begin();
		iter != m_setCtlID.end(); ++iter)
	{
		(iter == m_setCtlID.begin())
			? str.Format("%d", *iter) 
			: str.Format("%s,%d", str, *iter);
	}
}

CObjectSkin* CObjectSkin::FindID(int nID, bool & bMatch)
{
	bMatch = false;
	if(m_setCtlID.size() == 0)
	{
		return this;
	}

	if(m_setCtlID.find(nID) == m_setCtlID.end())
	{
		return NULL;
	}
	else
	{
		bMatch = true;
		return this;
	}
}

BOOL CObjectSkin::DrawImageRect(CDC *pDC, const CRect& rtDest,SkinImageRect & imageRect)
{
	CSkinBitmap *pImage = GetImages()->FindImage(imageRect.strImageName);
	if(pImage == NULL)
		return FALSE;

	pImage->Draw(pDC, (LPCRECT)rtDest,imageRect.rtImagePos);
	return TRUE;
}
BOOL CObjectSkin::TransDrawImageRect( CDC *pDC,const CRect& rtDest,SkinImageRect & imageRect,COLORREF crColour )
{
    CSkinBitmap *pImage = GetImages()->FindImage(imageRect.strImageName);
    if(!pImage)
        return FALSE;

    pImage->TransparentDraw(pDC,crColour,&rtDest,imageRect.rtImagePos);
    return TRUE;
}
BOOL CObjectSkin::DrawImageSection( CDC *pDC, const CRect& rtDest,SkinImageSection &imageSection)
{
    return DrawImage4in1(pDC, rtDest, imageSection, false, false);
}
BOOL CObjectSkin::TransDrawImageSection( CDC *pDC, const CRect& rtDest,SkinImageSection &imageSection,COLORREF crColour)
{
    return DrawImage4in1(pDC, rtDest, imageSection, false, true);
}
BOOL CObjectSkin::DrawImageBorder( CDC *pDC, const CRect& rtDest,SkinImageSection &imageSection )
{
    return DrawImage4in1(pDC, rtDest, imageSection, true, false);
}
//this function not draw client area.
BOOL CObjectSkin::TransDrawImageBorder( CDC *pDC, const CRect& rtDest,SkinImageSection &imageSection,COLORREF crColour )
{
    return DrawImage4in1(pDC, rtDest, imageSection, true, true);
}

void CObjectSkin::Draw1( CSkinBitmap* pImage, bool bTrans, CDC *pDC, COLORREF crColour, LPRECT lpRectDst, LPRECT lpRectSrc /*= NULL*/ )
{
    bTrans ?  pImage->AllStretchTransDraw(pDC, crColour, lpRectDst, lpRectSrc) 
            : pImage->Draw(pDC, lpRectDst, lpRectSrc);
}

void CObjectSkin::Draw2( CSkinBitmap* pImage, bool bTrans, CDC *pDC, COLORREF crColour, LPRECT lpRectDst, LPRECT lpRectSrc /*= NULL*/ )
{
    bTrans ? pImage->TitleTransDraw(pDC, crColour, lpRectDst, lpRectSrc)
           : pImage->TitleDraw(pDC, lpRectDst, lpRectSrc);
}
//*********************
//* 1   *   2   * 3	*
//*********************
//* 4	*   5   * 6	* 
//*     *       *   *
//*********************
//* 7	*   8   * 9 *
//*********************
BOOL CObjectSkin::DrawImage4in1( CDC *pDC, const CRect& rtDest,SkinImageSection &imageSection, bool bBorder, bool bTrans)
{
    CSkinBitmap *pImage = GetImages()->FindImage(imageSection.strImageName);
    if(pImage == NULL)
        return FALSE;

    SkinRect src,dst;
    if(pImage)
    {
        // draw part one
        src.left	= imageSection.rtImagePos.left;
        src.top		= imageSection.rtImagePos.top ;
        src.right	= imageSection.rtImagePos.left + imageSection.marginImage.left;
        src.bottom	= imageSection.rtImagePos.top + imageSection.marginImage.top ;

        dst.left	= rtDest.left;
        dst.top		= rtDest.top ;
        dst.right	= rtDest.left + imageSection.marginImage.left;
        dst.bottom	= rtDest.top + imageSection.marginImage.top ;
        if(src.Width() != 0 && src.Height() != 0)
        {   //pImage->Draw(pDC,dst,src);
            Draw1(pImage, bTrans, pDC, 0, dst, src);
        }
        //draw part two
        src.left	= imageSection.rtImagePos.left + imageSection.marginImage.left;
        src.top		= imageSection.rtImagePos.top ;
        src.right	= imageSection.rtImagePos.right - imageSection.marginImage.right;
        src.bottom	= imageSection.rtImagePos.top + imageSection.marginImage.top ;

        dst.left	= rtDest.left + imageSection.marginImage.left;
        dst.top		= rtDest.top ;
        dst.right	= rtDest.right - imageSection.marginImage.right;
        dst.bottom	= rtDest.top + imageSection.marginImage.top ;
        if(src.Width() != 0 && src.Height() != 0)
        {
            if(imageSection.stretchDrawMode == keStretchAll ||
                imageSection.stretchDrawMode == keStretchTop)
                //pImage->Draw(pDC,dst,src);
            {
                Draw1(pImage, bTrans, pDC, 0, dst, src);
            }
            else
                Draw2(pImage, bTrans, pDC, 0, dst, src);
            //pImage->TitleDraw(pDC,dst,src);

        }
        //draw part three
        src.left	= imageSection.rtImagePos.right - imageSection.marginImage.right;
        src.top		= imageSection.rtImagePos.top ;
        src.right	= imageSection.rtImagePos.right ;
        src.bottom	= imageSection.rtImagePos.top + imageSection.marginImage.top ;

        dst.left	= rtDest.right - imageSection.marginImage.right;
        dst.top		= rtDest.top ;
        dst.right	= rtDest.right ;
        dst.bottom	= rtDest.top + imageSection.marginImage.top ;
        if(src.Width() != 0 && src.Height() != 0)
            //pImage->Draw(pDC,dst,src);
        {
            Draw1(pImage, bTrans, pDC, 0, dst, src);
        }
        //draw part four
        src.left	= imageSection.rtImagePos.left;
        src.top		= imageSection.rtImagePos.top + imageSection.marginImage.top ;
        src.right	= imageSection.rtImagePos.left + imageSection.marginImage.left;
        src.bottom	= imageSection.rtImagePos.bottom - imageSection.marginImage.bottom ;

        dst.left	= rtDest.left;
        dst.top		= rtDest.top + imageSection.marginImage.top ;
        dst.right	= rtDest.left + imageSection.marginImage.left;
        dst.bottom	= rtDest.bottom - imageSection.marginImage.bottom;
        if(src.Width() != 0 && src.Height() != 0)
        {
            if(imageSection.stretchDrawMode == keStretchAll ||
                imageSection.stretchDrawMode == keStretchLeft)
                //pImage->Draw(pDC,dst,src);
            {
                Draw1(pImage, bTrans, pDC, 0, dst, src);
            }
            else
                //pImage->TitleDraw(pDC,dst,src);
                Draw2(pImage, bTrans, pDC, 0, dst, src);

        }
        if (!bBorder)
        {
            //draw part five
            src.left	= imageSection.rtImagePos.left + imageSection.marginImage.left;
            src.top		= imageSection.rtImagePos.top + imageSection.marginImage.top;
            src.right	= imageSection.rtImagePos.right - imageSection.marginImage.right;
            src.bottom	= imageSection.rtImagePos.bottom - imageSection.marginImage.bottom;

            dst.left	= rtDest.left + imageSection.marginImage.left;
            dst.top		= rtDest.top + imageSection.marginImage.top;
            dst.right	= rtDest.right - imageSection.marginImage.right;
            dst.bottom	= rtDest.bottom - imageSection.marginImage.bottom;
            if(src.Width() != 0 && src.Height() != 0)
            {
                if(imageSection.stretchDrawMode == keStretchAll ||
                    imageSection.stretchDrawMode == keStretchClient)
                    //pImage->Draw(pDC,dst,src);
                {
                    Draw1(pImage, bTrans, pDC, 0, dst, src);
                }
                else
                    //pImage->TitleDraw(pDC,dst,src);
                    Draw2(pImage, bTrans, pDC, 0, dst, src);

            }
        }
        //draw part six
        src.left	= imageSection.rtImagePos.right - imageSection.marginImage.right;
        src.top		= imageSection.rtImagePos.top + imageSection.marginImage.top;
        src.right	= imageSection.rtImagePos.right;
        src.bottom	= imageSection.rtImagePos.bottom - imageSection.marginImage.bottom;

        dst.left	= rtDest.right - imageSection.marginImage.right;
        dst.top		= rtDest.top + imageSection.marginImage.top;
        dst.right	= rtDest.right;
        dst.bottom	= rtDest.bottom - imageSection.marginImage.bottom;
        if(src.Width() != 0 && src.Height() != 0)
        {
            if(imageSection.stretchDrawMode == keStretchAll ||
                imageSection.stretchDrawMode == keStretchRight)
                //pImage->Draw(pDC,dst,src);
            {
                Draw1(pImage, bTrans, pDC, 0, dst, src);
            }
            else
                //pImage->TitleDraw(pDC,dst,src);
                Draw2(pImage, bTrans, pDC, 0, dst, src);

        }

        //draw part seven
        src.left	= imageSection.rtImagePos.left;
        src.top		= imageSection.rtImagePos.bottom - imageSection.marginImage.bottom ;
        src.right	= imageSection.rtImagePos.left + imageSection.marginImage.left;
        src.bottom	= imageSection.rtImagePos.bottom ;

        dst.left	= rtDest.left;
        dst.top		= rtDest.bottom - imageSection.marginImage.bottom ;
        dst.right	= rtDest.left + imageSection.marginImage.left;
        dst.bottom	= rtDest.bottom ;
        if(src.Width() != 0 && src.Height() != 0)
            //pImage->Draw(pDC,dst,src);
        {
            Draw1(pImage, bTrans, pDC, 0, dst, src);
        }
        //draw part eight
        src.left	= imageSection.rtImagePos.left + imageSection.marginImage.left;
        src.top		= imageSection.rtImagePos.bottom - imageSection.marginImage.bottom ;
        src.right	= imageSection.rtImagePos.right - imageSection.marginImage.right;
        src.bottom	= imageSection.rtImagePos.bottom ;

        dst.left	= rtDest.left + imageSection.marginImage.left;
        dst.top		= rtDest.bottom - imageSection.marginImage.bottom ;
        dst.right	= rtDest.right - imageSection.marginImage.right;
        dst.bottom	= rtDest.bottom ;
        if(src.Width() != 0 && src.Height() != 0)
        {
            if(imageSection.stretchDrawMode == keStretchAll ||
                imageSection.stretchDrawMode == keStretchBottom)
                //pImage->Draw(pDC,dst,src);
            {
                Draw1(pImage, bTrans, pDC, 0, dst, src);
            }
            else
                //pImage->TitleDraw(pDC,dst,src);
                Draw2(pImage, bTrans, pDC, 0, dst, src);
        }
        //draw part nine
        src.left	= imageSection.rtImagePos.right - imageSection.marginImage.right;
        src.top		= imageSection.rtImagePos.bottom - imageSection.marginImage.bottom ;
        src.right	= imageSection.rtImagePos.right;
        src.bottom	= imageSection.rtImagePos.bottom ;

        dst.left	= rtDest.right - imageSection.marginImage.right;
        dst.top		= rtDest.bottom - imageSection.marginImage.bottom ;
        dst.right	= rtDest.right;
        dst.bottom	= rtDest.bottom ;
        if(src.Width() != 0 && src.Height() != 0)
            //pImage->Draw(pDC,dst,src);
        {
            Draw1(pImage, bTrans, pDC, 0, dst, src);
        }

    }

    return TRUE;
}